//
//  LiftIMClient.m
//  AAIM
//
//  Created by awh on 2019/12/4.
//  Copyright © 2019年 AAIM. All rights reserved.
//

#import "LiftIMClient.h"
#import "NSDictionary+JSONString.h"
#import "NSString+DictionaryValue.h"
//#import "LiftIMChatManager.h"

#import "BTMessageModel.h"


@import SocketIO;

@interface LiftIMClient()
@property(nonatomic, assign) NSInteger userid;

@property (nonatomic, strong) SocketIOClient *socket;
@property (nonatomic, strong) SocketManager* manager;
@property (nonatomic, copy) NSString *mySendString;//发送内容
@property (nonatomic, copy) NSString *myLoginName;//发送方
@property (nonatomic, copy) NSString *receiverName;//接收方
//发送完消息回调
@property(nonatomic, copy) void (^sendMessageCompleted)(NSDictionary *info, NSError *error);


/* 新加的  心跳机制 -- ios判断pingpong   ，10s验证一次 保持重连。*/
@property(nonatomic, assign) long long lastSeverHeartBeatTimestamp;
@property(nonatomic, strong) NSTimer *netWorkCheckTimer; // 检测网络定时器
@property(nonatomic, assign) NSInteger reConnectTimes; // 重连次数
@property(nonatomic, assign) NSInteger networkNotReachableTime; // 没有网络状态持续时间
@property(nonatomic, strong) NSTimer *heartBeatTimer;
@end

@implementation LiftIMClient
#pragma mark - public

static LiftIMClient *client = nil;

+ (instancetype)sharedClient {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        client = [[self alloc] init];
    });
    return client;
}

- (instancetype)init {
    if (self = [super init]) {
        _chatManager = [[LiftIMChatManager alloc] init];
        _systemManager = [[LiftIMSystemManger alloc] init];

    }
    return self;
}
- (void)connectWithUserid:(NSInteger)userid {
    KWeakSelf;
    NSString *urlstr =[NSString stringWithFormat:@"ws://%@:%@",LIFT_APP_USER_SOCKET_KEY,LIFT_APP_USER_PORT_KEY];
    NSURL* url = [[NSURL alloc] initWithString:urlstr];
    self.manager = [[SocketManager alloc] initWithSocketURL:url config:@{@"log": @YES, @"compress": @YES,@"extraHeaders":@{@"t":[LoginManager shareLoginManager].userModel.token,@"uuid":[LoginManager shareLoginManager].userModel.uuid,@"h":@"011001000001",@"k":@"www.liftIM.con"},@"doubleEncodeUTF8":@YES}];
    self.socket = self.manager.defaultSocket;
    //监听连接Socket连接是否成功
    [self.socket on:@"connect" callback:^(NSArray* data, SocketAckEmitter* ack) {
        //sokcet当前状态  notConnected
        switch (self.socket.status) {
            case 0:
                //                 notConnected
                NSLog(@"重置 socket：%@",data);
                break;
            case 1:
                //                disconnected
                NSLog(@"关闭连接 socket：%@",data);
                break;
            case 2:
                //                connecting
                NSLog(@"正在连接 socket：%@",data);
                [self.systemManager receiveSocketConnectStatusDidChanged:2];
                break;
            case 3:
             { //    case connected
                 [self.systemManager receiveSocketConnectStatusDidChanged:3];
                NSLog(@"连接成功 socket：%@",data);
                 [self startSendHeartBeat];//开启心跳
                dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                    [[self.socket emitWithAck:@"join" with:@[]] timingOutAfter:0 callback:^(NSArray * callbackArray) {
                        AAIMLog(@"sendjoin回调的数据=%@",callbackArray);
                    }];
                });
              }
                break;
            default:
                break;
        }
    }];
    
    //下发群聊消息
    [self.socket on:@"gchat" callback:^(NSArray* data, SocketAckEmitter* ack) {
        AAIMLog(@"下发群聊消息=%@",data);
//        AAIMLog(@"下发群聊消息ack=%@",ack);
        [data enumerateObjectsUsingBlock:^(NSDictionary * obj, NSUInteger idx, BOOL * _Nonnull stop) {
            if ([obj[@"code"] integerValue]==200) {
                NSDictionary * dataDic = [obj[@"data"] dictionaryValue];
                NSArray *chatArray= dataDic[@"chat"];
                [chatArray enumerateObjectsUsingBlock:^(NSDictionary * chatObj, NSUInteger idx, BOOL * _Nonnull stop) {
                    //收消息成功
                    BTMessageModel * messageModel =[BTMessageModel mj_objectWithKeyValues:chatObj];
                    messageModel.type=[NSString stringWithFormat:@"%@",dataDic[@"type"]];
                    messageModel.gidorfuuid=[NSString stringWithFormat:@"%@",dataDic[@"gidorfuuid"]];
                    messageModel.chatType=ChatTypeGroup;
                    messageModel.receiveUid= [messageModel.gId integerValue];
                    messageModel.username=messageModel.nickname;
                    [self receiveMessageWityChatType:ChatTypeGroup messageModel:messageModel];
                    [self sendServerCallBack:0 res:@[[NSNumber numberWithInteger:[messageModel.msg_id integerValue]]]];
                }];
            }
        }];

    }];

    //下发私聊消息
    [self.socket on:@"fchat" callback:^(NSArray* data, SocketAckEmitter* ack) {
        AAIMLog(@"下发私聊消息=%@",data);
//        AAIMLog(@"下发私聊消息ack=%@",ack);
        [data enumerateObjectsUsingBlock:^(NSDictionary * obj, NSUInteger idx, BOOL * _Nonnull stop) {
            if ([obj[@"code"] integerValue]==200) {
                NSDictionary * dataDic = [obj[@"data"] dictionaryValue];
                NSArray *chatArray= dataDic[@"chat"];
                [chatArray enumerateObjectsUsingBlock:^(NSDictionary * chatObj, NSUInteger idx, BOOL * _Nonnull stop) {
                    //收消息成功
                    BTMessageModel * messageModel =[BTMessageModel mj_objectWithKeyValues:chatObj];
                    messageModel.type=[NSString stringWithFormat:@"%@",dataDic[@"type"]];
                    messageModel.gidorfuuid=[NSString stringWithFormat:@"%@",dataDic[@"gidorfuuid"]];
                    messageModel.chatType=ChatTypeFriend;
                    messageModel.receiveUid= [messageModel.gidorfuuid integerValue];
                    [self receiveMessageWityChatType:ChatTypeFriend messageModel:messageModel];
                    [self sendServerCallBack:1 res:@[[NSNumber numberWithInteger:[messageModel.msg_id integerValue]]]];

                }];
            }
        }];
    }];
       //服务端下发系统消息
        [self.socket on:@"noticemessage" callback:^(NSArray* data, SocketAckEmitter* ack) {
            NSLog(@"下发系统消息 %@",data);
            [data enumerateObjectsUsingBlock:^(NSDictionary * obj, NSUInteger idx, BOOL * _Nonnull stop) {
                if ([obj[@"code"] integerValue]==200) {
                    NSDictionary * dataDic = [obj[@"data"] dictionaryValue];
                    NSArray *chatArray= dataDic[@"chat"];
                    [chatArray enumerateObjectsUsingBlock:^(NSDictionary * chatObj, NSUInteger idx, BOOL * _Nonnull stop) {
                        //收消息成功
                        BTMessageModel * messageModel =[BTMessageModel mj_objectWithKeyValues:chatObj];
                        messageModel.type=[NSString stringWithFormat:@"%@",dataDic[@"type"]];
                        messageModel.gidorfuuid=[NSString stringWithFormat:@"%@",dataDic[@"gidorfuuid"]];
                        messageModel.chatType=ChatTypeSystem;
                        [self receiveMessageWityChatType:ChatTypeSystem messageModel:messageModel];
                        [self sendServerCallBack:2 res:@[[NSNumber numberWithInteger:[messageModel.msg_id integerValue]]]];
                    }];
                }
            }];
            
            
        }];
 
//    //用户上线服务端下发未读私聊消息
    [self.socket on:@"fonlinelowerhair" callback:^(NSArray* data, SocketAckEmitter* ack) {
        NSMutableArray * msgArray=[NSMutableArray new];
        [data enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            if ([obj[@"code"] integerValue]==200) {
                NSDictionary * dataDic = [obj[@"data"] dictionaryValue];
                NSArray *chatArray= dataDic[@"chat"];
                [chatArray enumerateObjectsUsingBlock:^(NSDictionary * chatObj, NSUInteger idx, BOOL * _Nonnull stop) {
                    NSLog(@"111111111111111pppppppppp");
                    //收消息成功
                    BTMessageModel * messageModel =[BTMessageModel mj_objectWithKeyValues:chatObj];
                    messageModel.type=[NSString stringWithFormat:@"%@",dataDic[@"type"]];
                    messageModel.gidorfuuid=[NSString stringWithFormat:@"%@",dataDic[@"gidorfuuid"]];
                    messageModel.chatType=ChatTypeFriend;
                    messageModel.receiveUid= [messageModel.gidorfuuid integerValue];
                    [self receiveMessageWityChatType:ChatTypeFriend messageModel:messageModel];
                    [msgArray addObject:[NSNumber numberWithInteger:[messageModel.msg_id integerValue]]];
                }];
            }
        }];
        [self sendServerCallBack:1 res:msgArray];
        AAIMLog(@"用户上线服务端下发未读私聊消息=%@",data);
//        AAIMLog(@"下用户上线服务端下发未读私聊消息ack=%@",ack);
    }];
    
    //    //用户上线服务端下发未读群消息
    [self.socket on:@"onlinelowerhair" callback:^(NSArray* data, SocketAckEmitter* ack) {
        NSMutableArray * msgArray=[NSMutableArray new];
        [data enumerateObjectsUsingBlock:^(NSDictionary * obj, NSUInteger idx, BOOL * _Nonnull stop) {
            if ([obj[@"code"] integerValue]==200) {
                NSDictionary * dataDic = [obj[@"data"] dictionaryValue];
                NSArray *chatArray= dataDic[@"chat"];
                [chatArray enumerateObjectsUsingBlock:^(NSDictionary * chatObj, NSUInteger idx, BOOL * _Nonnull stop) {
                    //收消息成功
                    BTMessageModel * messageModel =[BTMessageModel mj_objectWithKeyValues:chatObj];
                    messageModel.type=[NSString stringWithFormat:@"%@",dataDic[@"type"]];
                    messageModel.gidorfuuid=[NSString stringWithFormat:@"%@",dataDic[@"gidorfuuid"]];
                    messageModel.chatType=ChatTypeGroup;
                    messageModel.receiveUid= [messageModel.gId integerValue];
                    messageModel.username=messageModel.nickname;
                    [self receiveMessageWityChatType:ChatTypeGroup messageModel:messageModel];
                    [msgArray addObject:[NSNumber numberWithInteger:[messageModel.msg_id integerValue]]];
                }];
            }
         }];
        [self sendServerCallBack:0 res:msgArray];
            AAIMLog(@"用户上线服务端下发未读群消息=%@",data);
//            AAIMLog(@"用户上线服务端下发未读群消息ack=%@",ack);
        }];
    
    [self.socket on:@"noticeonlinelowerhair" callback:^(NSArray * data, SocketAckEmitter * ack) {
        NSMutableArray * msgArray=[NSMutableArray new];
        NSLog(@"下发未读系统消息 %@",data);
        [data enumerateObjectsUsingBlock:^(NSDictionary * obj, NSUInteger idx, BOOL * _Nonnull stop) {
            if ([obj[@"code"] integerValue]==200) {
                NSDictionary * dataDic = [obj[@"data"] dictionaryValue];
                NSArray *chatArray= dataDic[@"chat"];
                [chatArray enumerateObjectsUsingBlock:^(NSDictionary * chatObj, NSUInteger idx, BOOL * _Nonnull stop) {
                    //收消息成功
                    BTMessageModel * messageModel =[BTMessageModel mj_objectWithKeyValues:chatObj];
                    messageModel.type=[NSString stringWithFormat:@"%@",dataDic[@"type"]];
                    messageModel.gidorfuuid=[NSString stringWithFormat:@"%@",dataDic[@"gidorfuuid"]];
                    messageModel.chatType=ChatTypeSystem;
                [self receiveMessageWityChatType:ChatTypeSystem messageModel:messageModel];
                    [msgArray addObject:[NSNumber numberWithInteger:[messageModel.msg_id integerValue]]];
                }];
            }
        }];
        [self sendServerCallBack:2 res:msgArray];
    }];
//    [self.socket onAny:^(SocketAnyEvent * _Nonnull event) {
//        NSLog(@"收到=1===%@",event.event);
//        NSLog(@"收到=====%@",event.items);
     /*此处 可以加  [self receiveSeverHeartBeat] */
//    }];
    [self.socket connect];
}
-(void)sendServerCallBack:(NSInteger)uptype res:(NSArray*)res
{
  NSDictionary *  messageInfo =@{@"data":@{@"uptype":[NSNumber numberWithInteger:uptype],@"res":res},@"sign":@"1111"};
    [[self.socket emitWithAck:@"upid" with:@[messageInfo.JSONString]]timingOutAfter:0 callback:^(NSArray * callbackArray) {
        NSLog(@"返回-----------------------：%@",callbackArray);
    }];
}
-(void)closeConnect
{
    [self stopHeartBeat];
    [self clearSocket];
    NSLog(@"关闭连接之后的状态=%ld",self.socket.status);
}
-(void)sendMessage:(id)data messageType:(NSInteger)messageType complete:(void (^)(NSDictionary *, NSError *))complete {
    if (self.socket.status != 3) {
        AAIMLog(@"socket.io未连接,消息发送失败");
        [self reconnet];//发送失败重连
        NSError *error = [NSError errorWithDomain:@"socketIO未连接成功" code:0 userInfo:nil];
        complete ? complete(nil, error) : nil;
        return;
    }
    switch (messageType) {
        case ChatTypeFriend:
        {
            [[self.socket emitWithAck:@"fmsg" with:@[data]] timingOutAfter:0 callback:^(NSArray * callbackArray) {
                AAIMLog(@"回调的数据=%@",callbackArray);
                [callbackArray enumerateObjectsUsingBlock:^(NSDictionary * obj, NSUInteger idx, BOOL * _Nonnull stop) {
                    if ([obj[@"code"] integerValue]==200) {
                        complete ? complete([obj[@"data"] dictionaryValue], nil) : nil;
                    }else
                    {
                        NSError *error = [NSError errorWithDomain:[NSString stringWithFormat:@"%@",obj[@"message"]] code:[obj[@"code"] integerValue] userInfo:nil];
                        complete ? complete(obj , error) : nil;
                    }
                }];
            }];
        }
            break;
        case ChatTypeGroup:
        {

            [[self.socket emitWithAck:@"sendgmsg" with:@[data]] timingOutAfter:0 callback:^(NSArray * callbackArray) {
//                NSArray * array = callbackArray;
                AAIMLog(@"群回调的数据=%@",callbackArray);
                [callbackArray enumerateObjectsUsingBlock:^(NSDictionary * obj, NSUInteger idx, BOOL * _Nonnull stop) {
                    if ([obj[@"code"] integerValue]==200) {
                        complete ? complete([obj[@"data"] dictionaryValue], nil) : nil;
                    }else
                    {
                        NSError *error = [NSError errorWithDomain:[NSString stringWithFormat:@"%@",obj[@"message"]] code:[obj[@"code"] integerValue] userInfo:nil];
                        complete ? complete(obj , error) : nil;
                    }
                }];
            }];
        }
            break;
        case ChatTypeSystem:
        {
            
        }
            break;
            
        default:
            break;
    }
}
- (void)sendMessage:(id)data complete:(void (^)(NSDictionary *, NSError *))complete {
    //发送消息
    [self.socket emit:@"fmsg" with:data completion:^{
        self.sendMessageCompleted = complete;
    }];
}

- (void)receiveMessageWityChatType:(ChatType)chatType messageModel:(BTMessageModel *)messageModel {
    [self receiveSeverHeartBeat];//有收到消息 保证在线 ，
    messageModel.messageDirection = MessageDirectionReceive;
    if (messageModel.msgtype == MessageTypeText || messageModel.msgtype == MessageTypeImage || messageModel.msgtype == MessageTypeVoice) {
        messageModel.unreadCount = 1;
    }
    switch (chatType) {
        case ChatTypeFriend:
           [self.chatManager receivedMessages:@[messageModel]];
            break;
        case ChatTypeGroup:
            [self.chatManager receivedMessages:@[messageModel]];
            break;
        case ChatTypeSystem:
            [self.chatManager receivedMessages:@[messageModel]];
            break;
        default:
            break;
    }
    AAIMLog(@"收到的消息==%@",messageModel.nickname);
}
// 重连
- (void)reconnet {
    if (self.socket.status == 0 || self.socket.status == 1 || self.socket.status == 2 ||self.socket.status == 3) {
        [self closeConnect];
    }
    [self connectWithUserid:1];
}

#pragma mark - private   --- 新加
// 接收到服务器心跳
- (void)receiveSeverHeartBeat {
    _lastSeverHeartBeatTimestamp = [ChatTool shareChatTool].currentTimestamp;
}
- (void)clearSocket {
    [self.socket disconnect];
    self.socket = nil;
    
    [self stopHeartBeat];
    [self stopNetWorkCheckTimer];
}
// 开启心跳包定时器
- (void)startSendHeartBeat {
    [self stopHeartBeat];
    _reConnectTimes = 0;
    _lastSeverHeartBeatTimestamp = [ChatTool shareChatTool].currentTimestamp;
    _heartBeatTimer = [NSTimer scheduledTimerWithTimeInterval:10 target:self selector:@selector(sendHeartBeatMessage) userInfo:nil repeats:YES];
    [_heartBeatTimer fire];
}
// 发送心跳包
- (void)sendHeartBeatMessage {
    NSLog(@"发送心跳包");
    // 检测收到心跳时间
    if (_lastSeverHeartBeatTimestamp == 0) {
        _lastSeverHeartBeatTimestamp = [ChatTool shareChatTool].currentTimestamp;
    };
    long long  deltaTime = [ChatTool shareChatTool].currentTimestamp - _lastSeverHeartBeatTimestamp;
    if (deltaTime > 30 * 1000) {
        [self clearSocket];
        [self reconnet];
    }
    AAIMLog(@"距离上次收到心跳的时间间隔======%lld秒", deltaTime / 1000);
}
// 停止心跳包定时器
- (void)stopHeartBeat {
    [_heartBeatTimer invalidate];
    _heartBeatTimer = nil;
}
- (void)networkChecking {
    NSInteger networkStatus = AFNetworkReachabilityManager.sharedManager.networkReachabilityStatus;
    if(networkStatus == AFNetworkReachabilityStatusNotReachable || networkStatus == AFNetworkReachabilityStatusUnknown ) { // 没有网络，持续超过一定时间退出登录
        self.networkNotReachableTime ++ ;
        if (self.networkNotReachableTime > 10) {
            //关闭检查网络定时器
            [self stopNetWorkCheckTimer];
            //停止心跳
            [self stopHeartBeat];
            //没有网络 重练失败 退出
            [self.systemManager receiveSocketReconnectTimeout];
            self.networkNotReachableTime = 0;
        }
    } else {// 有网络去重连
        //关闭网络检测定时器
        [self stopNetWorkCheckTimer];
        //开始重连
        [self reconnet];
    }
    AAIMLog(@"检测网络定时器方法,当前网络状态：%ld", (long)networkStatus);
}
// 关闭检查网络定时器
- (void)stopNetWorkCheckTimer {
    WS(weakSelf);
    dispatch_main_async_safe(^{
        if(weakSelf.netWorkCheckTimer) {
            [weakSelf.netWorkCheckTimer invalidate];
            weakSelf.netWorkCheckTimer = nil;
        }
    });
}

@end
